package com.diligent.cloud.printer.client.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.canny.commons.model.Codes;
import com.diligent.cloud.primary.data.model.Result;
import com.diligent.cloud.printer.client.constant.PrinterConstant;
import com.diligent.cloud.printer.client.enums.ExportTypeEnum;
import com.diligent.cloud.printer.client.model.TemplateData;
import com.diligent.cloud.printer.client.service.PrinterFeignService;
import com.diligent.cloud.printer.client.service.PrinterService;
import com.diligent.cloud.printer.client.util.TemplateFileUtils;
import com.grid.models.RubylongCoreJacobImp;
import com.grid.models.enums.ExportType;
import com.grid.models.enums.GridVersion;
import com.grid.models.interfaces.RubylongCore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Description:
 * @Author: xf107397
 * @Date: Create：in 2020-07-02:11:47
 * @Modified By：
 */
@Service
@Slf4j
public class PrinterServiceImpl implements PrinterService {
    private static RubylongCore rlc= RubylongCoreJacobImp.getRubylongCore(GridVersion.V6_5);
    @Autowired
    private PrinterFeignService printerFeignService;

    @Override
    public ResponseEntity<Result> setTemplateAndData(TemplateData templateData) {
        Result result =  new Result();
        try{
             setTemplateData(templateData,result);
        }catch (Exception e){
            result.setMsg(e.getMessage());
            result.setCode(Codes.fail.getCode());
        }
        return ResponseEntity.ok(result);
    }

    /**
     * 数据格式:    {
     * 	"Table":[{
     * 		"doccode":"XXXX",
     * 		"ColorOrderCount":"XXX"
     *        }]
     * }
     * @param templateData
     * @param result
     */
    private void setTemplateData(TemplateData templateData,Result result) {
        if(StringUtils.isNotBlank(templateData.getDataJson())){
            //校验json格式
            Map<String,Object> dataMap;
            try {
                dataMap = JSONObject.parseObject(templateData.getDataJson(),Map.class);
                if(dataMap.size() != 1){
                    returnErrorMsg(result);
                }
            } catch (Exception e) {
                returnErrorMsg(result);
                return;
            }
            for(String key : dataMap.keySet()){
                Object obj = dataMap.get(key);
                if(obj instanceof List && ((List)obj).size()>0){
                    //将模板和数据合并成pdf文件
                    mergeTemplateData(templateData,result,true);
                }else {
                    returnErrorMsg(result);
                }
            }
        }else if(StringUtils.isNotBlank(templateData.getDataUrl())
                            && templateData.getDataUrl().contains(PrinterConstant.HTTP)){
            //将模板和数据合并成pdf文件
            mergeTemplateData(templateData,result,false);
        }else {
            returnErrorMsg(result);
        }
    }

    private void returnErrorMsg(Result result) {
        log.error("JSON数据格式不正确,参考如下：\n{\n" +
                "\t\"Table\":[{\n" +
                "\t\t\"key\":\"value\",\n" +
                "\t}]\n" +
                "}");
        result.setMsg(PrinterConstant.DATA_JSON_ERROR);
        result.setCode(Codes.fail.getCode());
    }

    /**
     * 将模板和数据合并成pdf文件
     * @param templateData
     * @param result
     * @param flag
     */
    private void mergeTemplateData(TemplateData templateData, Result result, boolean flag) {
        // 获得原始文件名
        String fileName = templateData.getTemplateFile()
                .getOriginalFilename() == null ? "" : templateData.getTemplateFile().getOriginalFilename();
        // 截取文件类型; 这里可以根据文件类型进行判断
        String fileType = fileName.substring(fileName.lastIndexOf('.'));
        if (!fileType.contains(PrinterConstant.GRID_GRF)) {
            result.setMsg(PrinterConstant.GRF_ERROR);
            result.setCode(Codes.fail.getCode());
            return;
        }
        if (StringUtils.isNotBlank(templateData.getTemplateXML())) {
            rlc.fnLoadFromStr(templateData.getTemplateXML());
            //保存合并文件
            saveMergeFile(result,templateData,flag);
        }else if(StringUtils.isNotBlank(templateData.getTemplateUrl())
                && templateData.getTemplateUrl().contains(PrinterConstant.HTTP)){
            rlc.fnLoadFromURL(templateData.getTemplateUrl());

            saveMergeFile(result,templateData,flag);
        }else if(templateData.getTemplateFile() != null && !templateData.getTemplateFile().isEmpty()){
            //获取本地模板文件。
            String templateFilePath = TemplateFileUtils.saveFile(templateData.getTemplateFile()
                                            ,PrinterConstant.TEMPLATE_TEMPLATE_PATH,fileType);
            File file = new File(templateFilePath);
            if(file.exists()){
                rlc.fnLoadFromFile(templateFilePath);
                //保存合并文件
                saveMergeFile(result,templateData,flag);
            }
        }else {
            result.setMsg(PrinterConstant.TEMPLATE_ERROR);
            result.setCode(Codes.fail.getCode());
        }
    }

    /**
     *  先设置模板，后设置数据，否则jvm崩溃。注意！
     * @param result
     * @param templateData
     * @param flag
     */
    private void saveMergeFile(Result result, TemplateData templateData, boolean flag) {
        if(flag){
            //设置数据的json ,先设置模板，后设置数据，否则jvm崩溃。注意！
            rlc.fnLoadDataFromXML(templateData.getDataJson());
        }else {
            //设置获取数据的连接 ,先设置模板，后设置数据，否则jvm崩溃。注意！
            rlc.fnLoadDataFromURL(templateData.getDataUrl());
        }
        File dir = new File(PrinterConstant.TEMPLATE_MERGE_PATH);
        if (!dir.exists()) {
            dir.mkdirs();//创建目录
        }
        String saveFilePath = PrinterConstant.TEMPLATE_MERGE_PATH + File.separatorChar
                        + UUID.randomUUID().toString().replace("-","");
        //设置导出格式。
        ExportType exportType =null;
        if(StringUtils.isBlank(templateData.getExportType())){
            exportType = ExportType.gretPDF;
            templateData.setExportType(ExportTypeEnum.getKey(exportType.getValue()));
        }else {
            Integer value = ExportTypeEnum.getValue(templateData.getExportType());
            if(value == null){
                result.setMsg(PrinterConstant.EXPORT_TYPE_ERROR);
                result.setCode(Codes.fail.getCode());
                return;
            }
            ExportType[] values = ExportType.values();
            for (ExportType type : values){
                if(type.getValue() == value){
                    exportType = type;
                    break;
                }
            }
        }
        //导出合并文件，转成pdf
        rlc.fnExportDirect(exportType, saveFilePath, false, false);

        //调用打印服务
        String filepath = saveFilePath + "." + templateData.getExportType();
        File file = new File(filepath);
        if(!file.exists()){
            result.setMsg(PrinterConstant.NOT_FIND_PRINT_FILE);
            result.setCode(Codes.fail.getCode());
            return;
        }
        DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file",
        //这个file对应feignClient中的MultipartFile参数名，写错就会报400 ："message":"Required request part 'file' is not present"这个错误，切记！
                MediaType.MULTIPART_FORM_DATA_VALUE, true, file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = fileItem.getOutputStream()) {
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }
        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        ResponseEntity<Result> resultResponseEntity = printerFeignService.printFile(multipartFile, null);
        //设置响应信息
        Result res = resultResponseEntity.getBody();
        if(res==null){
            result.setCode(Codes.success.getCode());
            result.setMsg(Codes.success.getMsg());
        }else{
            result.setCode(res.getCode());
            result.setMsg(res.getMsg());
        }
    }
}
